#include "cli.h"

int myMain(int argc, char *argv[]) {

    Options options = Options{};
    //std::cerr << argc << argv[0] << argv[1] << argv[2];
    OptionParser::parse(argc, argv, options);


    auto file{std::ifstream(options.filename)};
    if (!file.is_open()) {
        throw FileException(std::string("failed to open file:") + options.filename);
    }
//        file.seekg(std::ios::end);
//        auto len{file.tellg()};
//        file.seekg(std::ios::beg);
//        char *buffer{new char[len]};
//        file.read(buffer, len);
//        if (file.bad()) {
//            throw FileException(std::string("failed to read file:") + options.filename);
//        }

    std::string str{std::string((std::istreambuf_iterator<char>(file)),
                                std::istreambuf_iterator<char>())};
    //std::cout << str;
    file.close();

    std::ofstream solution{"solution.txt"};
    if (!solution.is_open()) {
        throw FileException("failed to open file `solution.txt` for output");
    }

    solute(str, solution, options);
    solution.close();

    return 0;
}

static int solute(std::string &wordList, std::ofstream &output, Options options) {
    char **result{alloc_result()};
    char **words;
    int len{splitStr(wordList, words)};

    switch (options.countType) {
        case CountType::NotSpecified:
            assert(false); // that should not happen, because relevant option has been checked
        case CountType::WordChainCount: {
            int result_len{gen_chains_all(words, len, result)};
            output << result_len << std::endl;
            for (int i = 0; i < result_len; ++i) {
                output << result[i] << std::endl;
            }
            free_result(result, result_len);
            break;
        }

        case CountType::MaxWordLengthWordChain: {
            int result_len{gen_chain_word(
                    words,
                    len,
                    result,
                    options.beginWith,
                    options.endWith,
                    options.notBeginWith,
                    options.isCycleAllowed)};
            for (int i = 0; i < result_len; ++i) {
                output << result[i] << '\n';
            }
            output << std::endl;
            free_result(result, result_len);
            break;
        }

        case CountType::MaxAlphabetLengthWordChain: {
            int result_len{gen_chain_char(
                    words,
                    len,
                    result,
                    options.beginWith,
                    options.endWith,
                    options.notBeginWith,
                    options.isCycleAllowed)};
            for (int i = 0; i < result_len; ++i) {
                output << result[i] << '\n';
            }
            output << std::endl;
            free_result(result, result_len);
            break;
        }

    }
    for (int i = 0; i < len; ++i) {
        delete[] words[i];
    }
    delete[] words;

    return 0;
}

static int splitStr(std::string &str, char **&words) {
    const char *cStr = str.c_str();
    auto pWordBegin{cStr};
    size_t wordLength{0};
    std::vector<char *> words_vec;
    while (pWordBegin[wordLength] != '\0') {
        if (is_alpha(pWordBegin[wordLength])) {
            wordLength++;
        } else {
            if (wordLength > 0) {
                char *word{new char[wordLength + 1]};
                strncpy_s(word, wordLength + 1, pWordBegin, wordLength);
                word[wordLength] = '\0';
                words_vec.push_back(word);
                pWordBegin += wordLength;
                wordLength = 0;
            } else {
                pWordBegin += 1;
            }
        }
    }
    if (wordLength > 0) {
        char *word{new char[wordLength + 1]};
        strncpy_s(word, wordLength + 1, pWordBegin, wordLength);
        word[wordLength] = '\0';
        words_vec.push_back(word);
    }
    // 有没有办法把内存`move out` vector?
    words = new char *[words_vec.size()];
    for (int i = 0; i < words_vec.size(); ++i) {
        words[i] = words_vec[i];
    }
    return static_cast<int>(words_vec.size());
}